package com.alpha.utils.quartz;

import com.alpha.exception.ExceptionUtil;
import com.alpha.pojo.dto.SysJobDTO;
import com.alpha.pojo.dto.SysJobLogDTO;
import com.alpha.service.SysJobLogService;
import com.alpha.utils.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;

import java.util.Date;

/**
 * 抽象quartz调用
 *
 * @author
 */
public abstract class AbstractQuartzJob implements Job {

    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);

    @Autowired
    private RestTemplate restTemplate = new RestTemplate();

    /**
     * 线程本地变量
     */
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        SysJobDTO sysJobDTO = new SysJobDTO();
        BeanUtils.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES), sysJobDTO);
        String invokeTarget = sysJobDTO.getInvokeTarget();
        if(invokeTarget.startsWith("http")){
            try {
                restTemplate.getForObject(invokeTarget, String.class);
                afterRest(context, sysJobDTO, null);
            }catch (Exception e){
                afterRest(context, sysJobDTO, e);
            }
        }else {
            try {
                before(context, sysJobDTO);
                if (sysJobDTO != null) {
                    doExecute(context, sysJobDTO);
                }
                after(context, sysJobDTO, null);
            } catch (Exception e) {
                log.error("任务执行异常  - ：", e);
                after(context, sysJobDTO, e);
            }
        }
    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param sysJobDTO  系统计划任务
     */
    protected void before(JobExecutionContext context, SysJobDTO sysJobDTO) {
        threadLocal.set(new Date());
    }

    /**
     * 执行后
     * @param context 工作执行上下文对象
     * @param sysJobDTO  系统计划任务
     */
    protected void afterRest(JobExecutionContext context, SysJobDTO sysJobDTO, Exception e) {
        final SysJobLogDTO sysJobLogDTO = new SysJobLogDTO();
        sysJobLogDTO.setJobName(sysJobDTO.getJobName());
        sysJobLogDTO.setJobGroup(sysJobDTO.getJobGroup());
        sysJobLogDTO.setInvokeTarget(sysJobDTO.getInvokeTarget());
        setData(sysJobLogDTO, e);
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     * @param sysJobDTO  系统计划任务
     */
    protected void after(JobExecutionContext context, SysJobDTO sysJobDTO, Exception e) {
        Date startTime = threadLocal.get();
        threadLocal.remove();

        final SysJobLogDTO sysJobLogDTO = new SysJobLogDTO();
        sysJobLogDTO.setJobName(sysJobDTO.getJobName());
        sysJobLogDTO.setJobGroup(sysJobDTO.getJobGroup());
        sysJobLogDTO.setInvokeTarget(sysJobDTO.getInvokeTarget());
        sysJobLogDTO.setStartTime(startTime);
        sysJobLogDTO.setStopTime(new Date());
        long runMs = sysJobLogDTO.getStopTime().getTime() - sysJobLogDTO.getStartTime().getTime();
        sysJobLogDTO.setJobMessage(sysJobLogDTO.getJobName() + " 总共耗时：" + runMs + "毫秒");
        setData(sysJobLogDTO, e);
    }

    /**
     * 执行方法，由子类重载
     *
     * @param context 工作执行上下文对象
     * @param sysJobDTO  系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, SysJobDTO sysJobDTO) throws Exception;

    protected void setData(SysJobLogDTO obj, Exception e){
        if (e != null) {
            obj.setStatus("1");
            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
            obj.setExceptionInfo(errorMsg);
        } else {
            obj.setStatus("0");
        }
        // 写入数据库当中
        SpringUtils.getBean(SysJobLogService.class).addJobLog(obj);
    }

}
